package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.Constants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 从物联网平台获取所有的产品, 并缓存到redis
     */
    @Override
    public void syncProductList() throws Exception {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1);
        request.setPageSize(200);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryProductListResponse response = client.queryProductList(request);
        if (response.getBody().success) {
            List<ProductVo> productVos = JSONUtil.toList(JSONUtil.toJsonStr(response.getBody().getData().getList().getProductInfo()), ProductVo.class);
            redisTemplate.opsForValue().set(Constants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVos));
        } else {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
    }

    /**
     * 查询redis中缓存的所有产品信息
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        String json = redisTemplate.opsForValue().get(Constants.ALL_PRODUCT_KEY);
        if (ObjectUtil.isNotEmpty(json)) {
            return JSONUtil.toList(json, ProductVo.class);
        } else {
            //为了预防空指针问题, 一般我们都会返回一个空的集合
            return new ArrayList<>(0);
        }
    }

    /**
     * 注册设备到物联网平台
     *
     * @param deviceDto
     * @return
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) throws Exception {
        //1. 判断名字是否重复, 如果重复则抛出异常
        Integer count = deviceMapper.countDeviceByName(deviceDto.getDeviceName());
        if (count > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }

        //2. 注册设备到阿里云的iot平台
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse response = client.registerDevice(request);

        //3. 判断阿里云返回的结果是否正确, 如果不正确则抛出异常
        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //4. 创建pojo拷贝dto的数据, 然后从阿里云的返回值中获取iot_id的值
        Device device = new Device();
        BeanUtil.copyProperties(deviceDto, device);

        device.setIotId(response.getBody().getData().getIotId());

        //4.1 发送请求查询产品的名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(device.getProductKey());
        QueryProductResponse queryProductResponse = client.queryProduct(queryProductRequest);
        if (!queryProductResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        device.setProductName(queryProductResponse.getBody().getData().getProductName());

        //5. 判断设备的安装位置是否是随身设备, 如果是那么安装位置要设置为-1
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }

        //6. 插入设备的数据
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            //7. 如果插入设备的数据的过程中抛了异常, 则需要删除iot中的设备
            DeleteDeviceRequest req = new DeleteDeviceRequest();
            req.setDeviceName(device.getDeviceName());
            req.setIotId(device.getIotId());
            req.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            req.setProductKey(device.getProductKey());
            DeleteDeviceResponse deviceResponse = client.deleteDevice(req);
            if (!deviceResponse.getBody().success) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        }
    }

    /**
     * 分页查询
     *
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> selectPage(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        Page<DeviceVo> page = deviceMapper.selectPage(devicePageQueryDto);
        return PageResponse.of(page, DeviceVo.class);
    }

    /**
     * 查询设备详细信息
     *
     * @param request
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) throws Exception {
        //1. 发送请求查询物联网平台中的设备数据
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response = client.queryDeviceDetail(request);

        //2. 判断是否查到了数据, 如果没有查到则抛出异常
        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        //3. 根据物联网平台id查询到数据库中的设备数据
        Device device = deviceMapper.selectByIotId(request.getIotId());

        //4. 合并物联网平台数据和数据库的数据
        DeviceVo vo = new DeviceVo();
        BeanUtil.copyProperties(device, vo);
        BeanUtil.copyProperties(response.getBody().getData(), vo, CopyOptions.create().ignoreNullValue());

        return vo;
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param request
     * @return
     */
    @Override
    public ResponseResult queryThingModelPublished(QueryThingModelPublishedRequest request) throws Exception {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response = client.queryThingModelPublished(request);

        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }

        QueryThingModelPublishedResponseBody.QueryThingModelPublishedResponseBodyData data = response.getBody().getData();

        return ResponseResult.success(data);
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param request
     * @return
     */
    @Override
    public ResponseResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) throws Exception {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response = client.queryDevicePropertyStatus(request);

        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }

        QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData data = response.getBody().getData();

        return ResponseResult.success(data);
    }

    /**
     * 修改设备备注名称
     *
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDevice(DeviceDto dto) throws Exception {
        Device device = BeanUtil.copyProperties(dto, Device.class);
        try {
            deviceMapper.updateByPrimaryKey(device);
        } catch (Exception e) {
            throw new RuntimeException("修改设备名称失败");
        }

        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo info = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        info.setDeviceName(dto.getDeviceName());
        info.setNickname(dto.getNickname());
        info.setProductKey(dto.getProductKey());
        info.setIotId(dto.getIotId());

        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> infoList = new ArrayList<>();
        infoList.add(info);

        request.setDeviceNicknameInfo(infoList);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        BatchUpdateDeviceNicknameResponse response = client.batchUpdateDeviceNickname(request);

        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

    }

    /**
     * 删除设备
     *
     * @param request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDevice(DeleteDeviceRequest request) throws Exception {
        try {
            deviceMapper.deleteByIotId(request.getProductKey(), request.getIotId());
        } catch (NumberFormatException e) {
            throw new RuntimeException("删除设备失败");
        }

        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        DeleteDeviceResponse response = client.deleteDevice(request);
        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }
}
